﻿using Koala.Pro.Common;
using Koala.Pro.Core;
using Koala.Pro.Core.Dto;
using Koala.Pro.Core.Models;
using SqlSugar;

namespace Koala.Pro.Services
{
    public class MenuService : MyCrudService<MenuInfo, string, MenuPagedDto>, IMenuService, IMyCrudService<MenuInfo, string, MenuPagedDto>, ITransientDependency, IDependency
    {
        private IRoleService _roleService;

        public MenuService(IApiUserSession currentApiUser, IRoleService roleService)
        {
            base.CurrentApiUser = currentApiUser;
            _roleService = roleService;
        }

        public override Task<Dictionary<string, string>> GetColumnNameAlias()
        {
            return Task.FromResult(new Dictionary<string, string>
        {
            { "PID", "父ID" },
            { "Name", "显示名称" },
            { "Icon", "图标" },
            { "Seq", "排序" },
            { "FunctionId", "功能ID" },
            { "Visible", "是否可见" },
            { "Expand", "是否展开" },
            { "WinformType", "Winform窗体类型" },
            { "WpfType", "WPF窗体类型" },
            { "Url", "Web界面Url地址" },
            { "WebIcon", "Web界面的菜单图标" },
            { "SystemType_ID", "系统编号" },
            { "Creator", "创建人" },
            { "Creator_ID", "创建人ID" },
            { "CreateTime", "创建时间" },
            { "Editor", "编辑人" },
            { "Editor_ID", "编辑人ID" },
            { "EditTime", "编辑时间" },
            { "Deleted", "是否已删除" },
            { "EmbedIcon", "图标字节" },
            { "Tag", "特殊标签" }
        });
        }

        protected override ISugarQueryable<MenuInfo> CreateFilteredQueryAsync(MenuPagedDto input)
        {
            return base.CreateFilteredQueryAsync(input).WhereIF(!input.ExcludeId.IsNullOrWhiteSpace(), (MenuInfo t) => t.Id != input.ExcludeId).WhereIF(!input.PID.IsNullOrWhiteSpace(), (MenuInfo s) => s.PID == input.PID)
                .WhereIF(!input.Name.IsNullOrWhiteSpace(), (MenuInfo t) => t.Name.Contains(input.Name))
                .WhereIF(!input.Icon.IsNullOrWhiteSpace(), (MenuInfo t) => t.Icon.Contains(input.Icon))
                .WhereIF(!input.Seq.IsNullOrWhiteSpace(), (MenuInfo t) => t.Seq.Contains(input.Seq))
                .WhereIF(!input.FunctionId.IsNullOrWhiteSpace(), (MenuInfo t) => t.FunctionId.Contains(input.FunctionId))
                .WhereIF(input.Visible.HasValue, (MenuInfo s) => s.Visible == (int?)input.Visible.Value)
                .WhereIF(input.Expand.HasValue, (MenuInfo s) => s.Expand == (int?)input.Expand.Value)
                .WhereIF(!input.WinformType.IsNullOrWhiteSpace(), (MenuInfo t) => t.WinformType.Contains(input.WinformType))
                .WhereIF(!input.WpfType.IsNullOrWhiteSpace(), (MenuInfo t) => t.WpfType.Contains(input.WpfType))
                .WhereIF(!input.Url.IsNullOrWhiteSpace(), (MenuInfo t) => t.Url.Contains(input.Url))
                .WhereIF(!input.WebIcon.IsNullOrWhiteSpace(), (MenuInfo t) => t.WebIcon.Contains(input.WebIcon))
                .WhereIF(!input.SystemType_ID.IsNullOrWhiteSpace(), (MenuInfo t) => t.SystemType_ID.Contains(input.SystemType_ID))
                .WhereIF(!input.Creator.IsNullOrWhiteSpace(), (MenuInfo t) => t.Creator.Contains(input.Creator))
                .WhereIF(!input.Creator_ID.IsNullOrWhiteSpace(), (MenuInfo t) => t.Creator_ID.Contains(input.Creator_ID))
                .WhereIF(input.CreateTimeStart.HasValue, (MenuInfo s) => s.CreateTime >= input.CreateTimeStart.Value)
                .WhereIF(input.CreateTimeEnd.HasValue, (MenuInfo s) => s.CreateTime <= input.CreateTimeEnd.Value)
                .WhereIF(!input.Editor.IsNullOrWhiteSpace(), (MenuInfo t) => t.Editor.Contains(input.Editor))
                .WhereIF(!input.Editor_ID.IsNullOrWhiteSpace(), (MenuInfo t) => t.Editor_ID.Contains(input.Editor_ID))
                .WhereIF(input.EditTimeStart.HasValue, (MenuInfo s) => s.EditTime >= input.EditTimeStart.Value)
                .WhereIF(input.EditTimeEnd.HasValue, (MenuInfo s) => s.EditTime <= input.EditTimeEnd.Value)
                .WhereIF(input.Deleted.HasValue, (MenuInfo s) => s.Deleted == input.Deleted)
                .WhereIF(!input.Tag.IsNullOrWhiteSpace(), (MenuInfo t) => t.Tag.Contains(input.Tag));
        }

        protected override ISugarQueryable<MenuInfo> ApplyDefaultSorting(ISugarQueryable<MenuInfo> query)
        {
            return from s in query
                   orderby s.Seq
                   orderby s.CreateTime
                   select s;
        }

        public async Task<List<MenuInfo>> GetMenuNodesByPID(string pid, string typeID)
        {
            return await (from t in base.Client.GetSimpleClient<MenuInfo>().AsSugarClient().Queryable<MenuInfo>()
                    .WhereIF(!typeID.IsNullOrWhiteSpace(), (MenuInfo t) => t.SystemType_ID == typeID)
                          orderby t.Seq
                          select t).ToTreeAsync((MenuInfo t) => t.Children, (MenuInfo t) => t.PID, pid);
        }

        public async Task<List<MenuInfo>> GetTree(string systemType)
        {
            string pid = "-1";
            return await GetMenuNodesByPID(pid, systemType);
        }

        public async Task<List<MenuInfo>> GetMenuNodes(string roleIDs, string typeID)
        {
            var sqlSugarClient = base.Client.GetSimpleClient<MenuInfo>().AsSugarClient();
            List<string> roleIdList = roleIDs?.Split([',']).ToList();
            if (roleIdList != null)
            {
                //return await (from t in sqlSugarClient.Queryable((MenuInfo t, Role_MenuInfo m) => t.Id == m.Menu_ID && roleIdList.Contains(m.Role_ID.ToString())).WhereIF(!typeID.IsNullOrWhiteSpace(), (MenuInfo t) => t.SystemType_ID == typeID)
                //              select (t) into t
                //              orderby t.Seq
                //              select t).ToTreeAsync((MenuInfo t) => t.Children, (MenuInfo t) => t.PID, "-1");

                var distinctIds = await sqlSugarClient.Queryable((MenuInfo t, Role_MenuInfo m) =>
                    t.Id == m.Menu_ID && roleIdList.Contains(m.Role_ID.ToString()))
                    .WhereIF(!typeID.IsNullOrWhiteSpace(), (MenuInfo t) => t.SystemType_ID == typeID)
                    .Select((MenuInfo t) => new { t.Id })
                    .Distinct()
                    .ToListAsync();

                var menuList = await sqlSugarClient.Queryable<MenuInfo>()
                    .Where(t => distinctIds.Select(id => id.Id).Contains(t.Id))
                    .OrderBy(t => t.Seq)
                    .ToTreeAsync((MenuInfo t) => t.Children, (MenuInfo t) => t.PID, "-1");

                return menuList;
            }
            return new List<MenuInfo>();
        }

        public async Task<List<MenuInfo>> GetMenuNodesByUser(int userID, string typeID)
        {
            var menuList = new List<MenuInfo>();
            try
            {
                List<RoleInfo> list = await _roleService.GetRolesByUser(userID);
                if (list.Count > 0)
                {
                    string text = string.Join(",", list.Select((RoleInfo s) => s.Id));
                    text = text.Trim([',']);
                    menuList = await GetMenuNodes(text, typeID);
                }
            }
            catch (Exception ex) 
            { 
            
            }
            
            return menuList;
        }

        public async Task<List<MenuInfo>> GetMenus(string roleIDs, string typeID)
        {
            List<string> roleIdList = roleIDs?.Split(new char[1] { ',' }).ToList();
            if (roleIdList != null)
            {
                return await (from t in base.Client.Queryable((MenuInfo t, Role_MenuInfo m) => t.Id == m.Menu_ID && roleIdList.Contains(m.Role_ID.ToString())).WhereIF(!typeID.IsNullOrWhiteSpace(), (MenuInfo t) => t.SystemType_ID == typeID)
                              select (t) into t
                              orderby t.Seq
                              select t).ToListAsync();
            }
            return new List<MenuInfo>();
        }

        public async Task<List<MenuInfo>> GetMenusByRole(int roleID, string typeID)
        {
            return await GetMenus(roleID.ToString(), typeID);
        }

        public async Task<ListResultDto<MenuInfo>> GetAllBySystemType(string systemType)
        {
            return await base.GetAllAsync((MenuInfo s) => s.SystemType_ID == systemType);
        }

        public async Task<string> GetName(string id)
        {
            return (await GetAsync(id))?.Name;
        }

        private IEnumerable<MenuInfo> GetLinks(IEnumerable<MenuInfo> list)
        {
            foreach (MenuInfo node in list)
            {
                yield return node;
                foreach (MenuInfo link in GetLinks(node.Children))
                {
                    yield return link;
                }
            }
        }
    }
}
